package com.yuno.mock.service;

import com.yuno.mock.dto.ExcelReadRequest;
import com.yuno.mock.dto.ExcelReadResult;
import com.yuno.mock.reader.impl.FastExcelReader;
import com.yuno.mock.util.ThreadPoolManager;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.FileInputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.*;

/**
 * Excel读取服务
 * 
 * @author yuno
 * @since 2024-01-01
 */
@Service
public class ExcelReaderService {
    
    private static final Logger log = LoggerFactory.getLogger(ExcelReaderService.class);
    
    @Autowired
    private FastExcelReader fastExcelReader;
    
    private final Map<String, CompletableFuture<ExcelReadResult>> runningTasks = new ConcurrentHashMap<>();
    private final Map<String, Double> progressMap = new ConcurrentHashMap<>();
    private final Map<String, String> taskStatusMap = new ConcurrentHashMap<>();
    
    /**
     * 同步读取Excel
     */
    public ExcelReadResult readExcelSync(ExcelReadRequest request) {
        log.info("开始同步读取Excel文件: {}", request.getFilePath());
        
        try {
            // 验证请求参数
            validateRequest(request);
            
            // 初始化进度跟踪
            if (request.getEnableProgressCallback()) {
                progressMap.put(request.getTaskId(), 0.0);
                taskStatusMap.put(request.getTaskId(), "RUNNING");
            }
            
            // 执行Excel读取
            ExcelReadResult result = performExcelRead(request);
            
            // 清理进度跟踪
            if (request.getEnableProgressCallback()) {
                progressMap.remove(request.getTaskId());
                taskStatusMap.remove(request.getTaskId());
            }
            
            log.info("同步读取Excel完成: {}, 总行数: {}", request.getFilePath(), result.getTotalRows());
            return result;
            
        } catch (Exception e) {
            log.error("同步读取Excel失败: {}, 错误: {}", request.getFilePath(), e.getMessage(), e);
            
            // 清理进度跟踪
            if (request.getEnableProgressCallback()) {
                progressMap.remove(request.getTaskId());
                taskStatusMap.put(request.getTaskId(), "FAILED");
            }
            
            throw new RuntimeException("Excel读取失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 异步读取Excel
     */
    public CompletableFuture<ExcelReadResult> readExcelAsync(ExcelReadRequest request) {
        log.info("开始异步读取Excel文件: {}", request.getFilePath());
        
        try {
            // 验证请求参数
            validateRequest(request);
            
            // 初始化进度跟踪
            progressMap.put(request.getTaskId(), 0.0);
            taskStatusMap.put(request.getTaskId(), "RUNNING");
            
            // 创建异步任务
            CompletableFuture<ExcelReadResult> future = CompletableFuture.supplyAsync(() -> {
                try {
                    return performExcelRead(request);
                } catch (Exception e) {
                    log.error("异步读取Excel失败: {}, 错误: {}", request.getFilePath(), e.getMessage(), e);
                    taskStatusMap.put(request.getTaskId(), "FAILED");
                    throw new RuntimeException("Excel读取失败: " + e.getMessage(), e);
                }
            }, ThreadPoolManager.getExecutor());
            
            // 保存任务引用
            runningTasks.put(request.getTaskId(), future);
            
            // 任务完成后清理
            future.whenComplete((result, throwable) -> {
                runningTasks.remove(request.getTaskId());
                progressMap.remove(request.getTaskId());
                if (throwable == null) {
                    taskStatusMap.put(request.getTaskId(), "COMPLETED");
                    log.info("异步读取Excel完成: {}, 总行数: {}", request.getFilePath(), result.getTotalRows());
                } else {
                    taskStatusMap.put(request.getTaskId(), "FAILED");
                }
            });
            
            return future;
            
        } catch (Exception e) {
            log.error("启动异步读取Excel失败: {}, 错误: {}", request.getFilePath(), e.getMessage(), e);
            progressMap.remove(request.getTaskId());
            taskStatusMap.put(request.getTaskId(), "FAILED");
            throw new RuntimeException("启动异步读取失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 异步读取Excel（返回任务ID）
     */
    public String readExcelAsyncWithTaskId(ExcelReadRequest request) {
        log.info("开始异步读取Excel文件: {}", request.getFilePath());
        
        try {
            // 验证请求参数
            validateRequest(request);
            
            // 初始化进度跟踪
            progressMap.put(request.getTaskId(), 0.0);
            taskStatusMap.put(request.getTaskId(), "RUNNING");
            
            // 创建异步任务
            CompletableFuture<ExcelReadResult> future = CompletableFuture.supplyAsync(() -> {
                try {
                    return performExcelRead(request);
                } catch (Exception e) {
                    log.error("异步读取Excel失败: {}, 错误: {}", request.getFilePath(), e.getMessage(), e);
                    taskStatusMap.put(request.getTaskId(), "FAILED");
                    throw new RuntimeException("Excel读取失败: " + e.getMessage(), e);
                }
            }, ThreadPoolManager.getExecutor());
            
            // 保存任务引用
            runningTasks.put(request.getTaskId(), future);
            
            // 任务完成后清理
            future.whenComplete((result, throwable) -> {
                runningTasks.remove(request.getTaskId());
                progressMap.remove(request.getTaskId());
                if (throwable == null) {
                    taskStatusMap.put(request.getTaskId(), "COMPLETED");
                    log.info("异步读取Excel完成: {}, 总行数: {}", request.getFilePath(), result.getTotalRows());
                } else {
                    taskStatusMap.put(request.getTaskId(), "FAILED");
                }
            });
            
            return request.getTaskId();
            
        } catch (Exception e) {
            log.error("启动异步读取Excel失败: {}, 错误: {}", request.getFilePath(), e.getMessage(), e);
            progressMap.remove(request.getTaskId());
            taskStatusMap.put(request.getTaskId(), "FAILED");
            throw new RuntimeException("启动异步读取失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 分片读取Excel
     */
    public List<String> readExcelWithSharding(ExcelReadRequest request) {
        log.info("开始分片读取Excel文件: {}, 分片大小: {}", request.getFilePath(), request.getShardSize());
        
        try {
            // 验证请求参数
            validateRequest(request);
            
            // 获取总行数
            long totalRows = getTotalRowCount(request.getFilePath(), request.getSheetName());
            log.info("Excel文件总行数: {}", totalRows);
            
            // 创建分片
            List<ExcelReadRequest> shards = createShards(request, totalRows);
            log.info("创建了{}个分片", shards.size());
            
            List<String> taskIds = new ArrayList<>();
            
            // 为每个分片启动异步任务
            for (ExcelReadRequest shard : shards) {
                String taskId = readExcelAsyncWithTaskId(shard);
                taskIds.add(taskId);
            }
            
            log.info("分片读取Excel启动完成: {}, 分片数: {}", request.getFilePath(), taskIds.size());
            return taskIds;
            
        } catch (Exception e) {
            log.error("分片读取Excel失败: {}, 错误: {}", request.getFilePath(), e.getMessage(), e);
            throw new RuntimeException("分片读取失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 获取任务进度
     */
    public Double getProgress(String taskId) {
        return progressMap.get(taskId);
    }
    
    /**
     * 获取任务状态
     */
    public String getTaskStatus(String taskId) {
        return taskStatusMap.get(taskId);
    }
    
    /**
     * 获取任务结果
     */
    public ExcelReadResult getTaskResult(String taskId) {
        CompletableFuture<ExcelReadResult> future = runningTasks.get(taskId);
        if (future == null) {
            return null;
        }
        
        try {
            if (future.isDone()) {
                return future.get();
            } else {
                return null; // 任务还在运行中
            }
        } catch (Exception e) {
            log.error("获取任务结果失败: {}, 错误: {}", taskId, e.getMessage(), e);
            return null;
        }
    }
    
    /**
     * 取消任务
     */
    public boolean cancelTask(String taskId) {
        CompletableFuture<ExcelReadResult> future = runningTasks.get(taskId);
        if (future != null) {
            boolean cancelled = future.cancel(true);
            if (cancelled) {
                runningTasks.remove(taskId);
                progressMap.remove(taskId);
                taskStatusMap.put(taskId, "CANCELLED");
                log.info("任务已取消: {}", taskId);
            }
            return cancelled;
        }
        return false;
    }
    
    /**
     * 获取所有运行中的任务
     */
    public Set<String> getRunningTasks() {
        return new HashSet<>(runningTasks.keySet());
    }
    
    /**
     * 验证请求参数
     */
    private void validateRequest(ExcelReadRequest request) {
        if (request == null) {
            throw new IllegalArgumentException("请求参数不能为空");
        }
        if (request.getFilePath() == null || request.getFilePath().trim().isEmpty()) {
            throw new IllegalArgumentException("文件路径不能为空");
        }
        if (request.getTaskId() == null || request.getTaskId().trim().isEmpty()) {
            throw new IllegalArgumentException("任务ID不能为空");
        }
    }
    
    /**
     * 执行Excel读取
     */
    private ExcelReadResult performExcelRead(ExcelReadRequest request) {
        log.info("执行Excel读取: {}", request.getFilePath());
        
        try {
            // 使用FastExcelReader进行实际的Excel读取
            return fastExcelReader.readExcel(request);
        } catch (Exception e) {
            log.error("Excel读取失败: {}, 错误: {}", request.getFilePath(), e.getMessage(), e);
            throw new RuntimeException("Excel读取失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 获取总行数
     */
    private long getTotalRowCount(String filePath, String sheetName) {
        // TODO: 实现获取总行数的逻辑
        return 1000L; // 临时返回固定值
    }
    
    /**
     * 创建分片
     */
    private List<ExcelReadRequest> createShards(ExcelReadRequest originalRequest, long totalRows) {
        List<ExcelReadRequest> shards = new ArrayList<>();
        
        int shardSize = originalRequest.getShardSize();
        if (shardSize <= 0) {
            shardSize = 1000; // 默认分片大小
        }
        
        for (long startRow = 0; startRow < totalRows; startRow += shardSize) {
            long endRow = Math.min(startRow + shardSize - 1, totalRows - 1);
            
            ExcelReadRequest shard = new ExcelReadRequest();
            shard.setFilePath(originalRequest.getFilePath());
            shard.setSheetName(originalRequest.getSheetName());
            shard.setStartRow((int) startRow);
            shard.setEndRow((int) endRow);
            shard.setTaskId(originalRequest.getTaskId() + "_shard_" + (startRow / shardSize));
            shard.setEnableProgressCallback(originalRequest.getEnableProgressCallback());
            
            shards.add(shard);
        }
        
        return shards;
    }
    
    /**
     * 获取系统健康状态
     */
    public Map<String, Object> getSystemHealth() {
        Map<String, Object> health = new HashMap<>();
        
        health.put("timestamp", LocalDateTime.now());
        health.put("runningTasks", runningTasks.size());
        health.put("totalTasks", taskStatusMap.size());
        health.put("threadPoolActive", ThreadPoolManager.getActiveCount());
        health.put("threadPoolSize", ThreadPoolManager.getPoolSize());
        
        return health;
    }
    
    /**
     * 获取Excel文件的所有Sheet页信息
     * 
     * @param filePath Excel文件路径
     * @return Sheet页信息列表
     */
    public List<Map<String, Object>> getExcelSheets(String filePath) {
        log.info("开始获取Excel文件Sheet页信息: {}", filePath);
        
        List<Map<String, Object>> sheets = new ArrayList<>();
        
        try (Workbook workbook = createWorkbook(filePath)) {
            int numberOfSheets = workbook.getNumberOfSheets();
            log.debug("Excel文件包含{}个Sheet页", numberOfSheets);
            
            for (int i = 0; i < numberOfSheets; i++) {
                Sheet sheet = workbook.getSheetAt(i);
                Map<String, Object> sheetInfo = new HashMap<>();
                
                sheetInfo.put("index", i);
                sheetInfo.put("name", sheet.getSheetName());
                sheetInfo.put("rowCount", sheet.getLastRowNum() + 1);
                
                // 获取第一行来确定列数
                Row firstRow = sheet.getRow(0);
                int columnCount = 0;
                if (firstRow != null) {
                    columnCount = firstRow.getLastCellNum();
                }
                sheetInfo.put("columnCount", columnCount);
                
                sheets.add(sheetInfo);
                log.debug("Sheet[{}]: name={}, rows={}, columns={}", 
                        i, sheet.getSheetName(), sheet.getLastRowNum() + 1, columnCount);
            }
            
            log.info("Excel文件Sheet页信息获取完成: {}, 共{}个Sheet页", filePath, numberOfSheets);
            
        } catch (Exception e) {
            log.error("获取Excel文件Sheet页信息失败: {}, 错误: {}", filePath, e.getMessage(), e);
            throw new RuntimeException("获取Sheet页信息失败: " + e.getMessage(), e);
        }
        
        return sheets;
    }

    /**
     * 创建Workbook对象
     * 
     * @param filePath Excel文件路径
     * @return Workbook对象
     * @throws IOException 文件读取异常
     */
    private Workbook createWorkbook(String filePath) throws IOException {
        FileInputStream fis = new FileInputStream(filePath);
        
        // 根据文件扩展名判断Excel版本
        if (filePath.toLowerCase().endsWith(".xlsx")) {
            return new XSSFWorkbook(fis);
        } else if (filePath.toLowerCase().endsWith(".xls")) {
            return new HSSFWorkbook(fis);
        } else {
            throw new IllegalArgumentException("不支持的文件格式，仅支持.xls和.xlsx文件");
        }
    }
    
    /**
     * 获取Excel文件信息
     */
    public Map<String, Object> getExcelInfo(ExcelReadRequest request) {
        log.info("获取Excel文件信息: {}", request.getFilePath());
        
        try {
            validateRequest(request);
            
            Map<String, Object> info = new HashMap<>();
            info.put("filePath", request.getFilePath());
            
            // 获取工作表信息
            List<Map<String, Object>> sheets = getExcelSheets(request.getFilePath());
            info.put("sheets", sheets);
            info.put("sheetCount", sheets.size());
            
            // 计算总行数
            long totalRows = sheets.stream()
                    .mapToLong(sheet -> (Long) sheet.get("rowCount"))
                    .sum();
            info.put("totalRows", totalRows);
            
            return info;
            
        } catch (Exception e) {
            log.error("获取Excel文件信息失败: {}, 错误: {}", request.getFilePath(), e.getMessage(), e);
            throw new RuntimeException("获取Excel文件信息失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 获取服务状态
     */
    public Map<String, Object> getServiceStatus() {
        Map<String, Object> status = new HashMap<>();
        
        try {
            // 基本状态
            status.put("status", "RUNNING");
            status.put("timestamp", System.currentTimeMillis());
            
            // 任务统计
            status.put("runningTasks", runningTasks.size());
            status.put("totalTasks", taskStatusMap.size());
            
            // 线程池状态
            Map<String, Object> threadPoolStatus = ThreadPoolManager.getStatus();
            status.put("threadPool", threadPoolStatus);
            
            // 内存使用情况
            Runtime runtime = Runtime.getRuntime();
            Map<String, Object> memory = new HashMap<>();
            memory.put("totalMemory", runtime.totalMemory());
            memory.put("freeMemory", runtime.freeMemory());
            memory.put("usedMemory", runtime.totalMemory() - runtime.freeMemory());
            memory.put("maxMemory", runtime.maxMemory());
            status.put("memory", memory);
            
            return status;
        } catch (Exception e) {
            log.error("获取服务状态失败: {}", e.getMessage(), e);
            Map<String, Object> errorStatus = new HashMap<>();
            errorStatus.put("status", "ERROR");
            errorStatus.put("message", "获取服务状态失败: " + e.getMessage());
            errorStatus.put("timestamp", System.currentTimeMillis());
            return errorStatus;
        }
    }
    
    /**
     * 健康检查
     */
    public Map<String, Object> healthCheck() {
        Map<String, Object> health = new HashMap<>();
        
        try {
            // 检查基本功能
            health.put("status", "UP");
            health.put("timestamp", System.currentTimeMillis());
            
            // 检查线程池
            ThreadPoolExecutor executor = ThreadPoolManager.getExecutor();
            boolean threadPoolHealthy = !executor.isShutdown() && !executor.isTerminated();
            health.put("threadPool", threadPoolHealthy ? "UP" : "DOWN");
            
            // 检查内存使用
            Runtime runtime = Runtime.getRuntime();
            long usedMemory = runtime.totalMemory() - runtime.freeMemory();
            long maxMemory = runtime.maxMemory();
            double memoryUsage = (double) usedMemory / maxMemory;
            health.put("memoryUsage", memoryUsage);
            health.put("memoryStatus", memoryUsage < 0.9 ? "UP" : "WARNING");
            
            // 整体健康状态
            boolean isHealthy = threadPoolHealthy && memoryUsage < 0.95;
            health.put("overall", isHealthy ? "UP" : "DOWN");
            
        } catch (Exception e) {
            log.error("健康检查失败: {}", e.getMessage(), e);
            health.put("status", "DOWN");
            health.put("error", e.getMessage());
        }
        
        return health;
    }
}